package demo;

import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import pojo.Article;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * es的创建索引+创建映射
 *
 * @author Taeyang
 * @date 2025/4/27
 */
public class Demo1 {

    /**
     * 高亮查询：高亮并不是之间拼接在原文档域中的，需要单独获取
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 高亮条件构建
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("content");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                // 表
                .setTypes("article")
                // 条件
                .setQuery(QueryBuilders.matchQuery("content", "数据"))
                // 排序
                .addSort("id", SortOrder.DESC)
                // 分页
                .setFrom(0)
                .setSize(101)
                // 高亮
                .highlighter(highlightBuilder)
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            // 文档域的原始数据
            String sourceAsString = hit.getSourceAsString();
            // 反序列化
            Article article = JSONObject.parseObject(sourceAsString, Article.class);
            // 获取高亮数据
            HighlightField highlightField = hit.getHighlightFields().get("content");
            if (highlightField != null) {
                String content = "";
                for (Text fragment : highlightField.getFragments()) {
                    content += fragment;
                }
                article.setContent(content);
            }
            System.out.println(article);
        }

        // 关闭连接
        client.close();
    }

    /**
     * 分页查询
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main12(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                // 表
                .setTypes("article")
                // 条件
                .setQuery(QueryBuilders.matchAllQuery())
                // 排序
                .addSort("id", SortOrder.DESC)
                // 分页
                .setFrom(0)
                .setSize(101)
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 组合查询：多条件组合boolquery
     * 数据库：a=? and b=? and c=? or d=?
     * es：must=and should=or mustNot=not
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main11(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("title", "搜索"))
                        .must(QueryBuilders.fuzzyQuery("content", "Elasticsearch"))
                        .must(QueryBuilders.rangeQuery("id").gte(55).lte(60))
                )
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 相似度查询：查2次，对输入的条件不分词，相似度的偏移量是2，就是错两个依然可以搜出来，这个可以控制，但是一般不调节，也不去用相似度查询
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main10(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.fuzzyQuery("content", "elasticsearch".toUpperCase()))
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 模糊查询：查2次，对输入的条件不分词
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main9(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.wildcardQuery("title", "ELASTICSEARCH".toLowerCase()))
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 词条查询：查2次，对输入的条件不分词
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main8(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.termQuery("title", "ELASTICSEARCH".toLowerCase()))
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 匹配查询：查2次，对输入的条件分词
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main7(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.matchQuery("title", "ELASTICSEARCH"))
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 字符串查询：查2次，对输入的条件分词
     *
     * @param args
     */
    public static void main6(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 字符串查询
        SearchResponse searchResponse = client.prepareSearch("java0315_new")
                .setTypes("article")
                .setQuery(QueryBuilders.queryStringQuery("ELASTICSEARCH").field("title"))
                .get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }

        // 关闭连接
        client.close();
    }

    /**
     * 查询单条数据：文档下标查询
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main5(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 文档下标查询：去哪个数据的哪张表查询文档下标（id）为什么的数据
        GetResponse getResponse = client.prepareGet("java0315_new", "article", "1").get();
        System.out.println(getResponse.getSource());
        // 关闭连接
        client.close();
    }

    /**
     * 查询所有数据：输出文档域
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main4(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 查询所有数据：去哪个数据的哪张表用什么样的条件去查数据
        SearchResponse searchResponse = client.prepareSearch("java0315_new").setTypes("article").setSize(101).setQuery(QueryBuilders.matchAllQuery()).get();
        // 获取全部命中的数据
        SearchHits hits = searchResponse.getHits();
        // 符合条件的总数据量
        System.out.println("符合条件的数据一共有：" + hits.getTotalHits().value);
        // 每条数据：es默认分页10条
        for (SearchHit hit : hits.getHits()) {
            System.out.println(hit.getSourceAsString());
        }
        // 关闭连接
        client.close();
    }

    /**
     * 创建数据：单条数据提交、批量数据新增
     *
     * @param args
     * @throws UnknownHostException
     */
    public static void main3(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 创建数据：单条数据提交、批量数据新增 -- 了解
        // 构建一个批量对象
        BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
        // for循环单条数据提交，循环一次提交一次
        for (long i = 1; i <= 100; i++) {
            // 构建对象
            Article article = new Article();
            // 这个id是刚好这条数据有一个属性叫做id，实际情况下这个id和下面的id保持一致，但是需要明白这两个id的本质是不一样的
            article.setId(i);
            article.setTitle(i + "：Elasticsearch 为所有类型的数据提供近乎实时的搜索和分析。");
            article.setContent(i + "：无论您拥有结构化或非结构化文本、数字数据还是地理空间数据，Elasticsearch 都能以支持快速搜索的方式高效地存储和索引它。" +
                    "您可以超越简单的数据检索和聚合信息来发现数据中的趋势和模式。随着您的数据和查询量的增长，Elasticsearch 的分布式特性使您的部署能够随之无缝增长。");
            // 10086 这个id才是这条数据的唯一标识，即文档下标
            // es给我们的是json，我们给es的也需要是json
            // 这里其实是对 10086 下标写了100次，es中没有冲突、修改的概念，只要两条数据的文档下标一样，后面的就会把前面的覆盖掉
            client.prepareIndex("java0315_new", "article", i + "").setSource(JSONObject.toJSONString(article), XContentType.JSON).get();
            // 循环的时候将数据添加到批量对象中
            bulkRequestBuilder.add(client.prepareIndex("java0315_new", "article", i + "").setSource(JSONObject.toJSONString(article), XContentType.JSON));
        }
        // 批量添加执行
        BulkResponse bulkResponse = bulkRequestBuilder.execute().actionGet();
        // 关闭连接
        client.close();
    }

    /**
     * 创建索引+映射
     *
     * @param args
     */
    public static void main2(String[] args) throws IOException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 如果创建索引失败可以先删除之后再重新构建
        // client.admin().indices().prepareDelete("java0315_new").get();
        // 创建索引：创建数据库并提交 prepareCreate 预创建 get 提交
        client.admin().indices().prepareCreate("java0315_new").get();
        // 构建映射，es原生提供的json构造器
        XContentBuilder builder = XContentFactory.jsonBuilder();
        // .startObject() 左大括号  .endObject() 右大括号  .field 键值对
        builder
                .startObject()
                .startObject("article")
                .startObject("properties")
                .startObject("id")
                .field("type", "long")
                .endObject()
                .startObject("title")
                .field("type", "text")
                .field("analyzer", "ik_max_word")
                .endObject()
                .startObject("content")
                .field("type", "text")
                .field("analyzer", "ik_max_word")
                .endObject()
                .endObject()
                .endObject()
                .endObject();
        // 构建映射请求体
        PutMappingRequest request = Requests.putMappingRequest("java0315_new").type("article").source(builder);
        // 保存映射，创建提交
        client.admin().indices().putMapping(request);
        // 关闭连接
        client.close();
    }

    /**
     * 创建索引：类似创建数据库
     *
     * @param args
     */
    public static void main1(String[] args) throws UnknownHostException {
        // 初始化客户端对象：Settings.EMPTY 当前是单点不是集群 -- TCP协议，后续高版本使用的是HTTP协议
        TransportClient client = new PreBuiltTransportClient(Settings.EMPTY);
        // 设置IP地址和端口号，有用户名密码则需要设置用户名密码，TCP端口号 9300 HTTP版本号 9200
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300));
        // 创建索引：创建数据库并提交 prepareCreate 预创建 get 提交
        client.admin().indices().prepareCreate("java0315").get();
        // 关闭连接
        client.close();
    }
}
